﻿package away3d.core.base ;


import away3d.animators.data.AnimationBase ;
import away3d.animators.data.NullAnimation ;
import away3d.arcane ;
import away3d.events.GeometryEvent ;
import away3d.library.assets.AssetType ;
import away3d.library.assets.IAsset ;
import away3d.library.assets.NamedAssetBase ;
import flash.events.EventDispatcher ;



/**
 * Geometry is a collection of SubGeometries, each of which contain the actual geometrical data such as vertices,
 * normals, uvs, etc. It also contains a reference to an animation class, which defines how the geometry moves.
 * A Geometry object is assigned to a Mesh, a scene graph occurence of the geometry, which in turn assigns
 * the SubGeometries to its respective SubMesh objects.
 *
 * 
 * 
 * @see away3d.core.base.SubGeometry
 * @see away3d.scenegraph.Mesh
 */
class Geometry extends NamedAssetBase implements IAsset
{
    
    
    private var _subGeometries : Vector<SubGeometry> ;
    public var _animation : AnimationBase ;
    
    
    
    /**
     * Creates a new Geometry object.
     */
    public function Geometry()
    {
        
        _subGeometries  = new Vector<SubGeometry>() ;
        _animation      = new NullAnimation() ;
        
    }
    
    
    public var assetType( get_assetType, null ) : String ;
    
    
    private function get_assetType() : String
    {
        
        return AssetType.GEOMETRY ;
        
    }
    
    
    public var animation( get_animation, set_animation ) : AnimationBase ;
    
    
    /**
     * The AnimationBase object used to animate the geometry.
     */
    private function get_animation() : AnimationBase
    {
        
        return _animation ;
        
    }
    
    
    private function set_animation( value : AnimationBase ) : AnimationBase
    {
        
        _animation = value ;
        if( hasEventListener( GeometryEvent.ANIMATION_CHANGED ) )
        {
            
            dispatchEvent( new GeometryEvent( GeometryEvent.ANIMATION_CHANGED ) ) ;
            
        }
        
    }
    
    
    /**
     * A collection of SubGeometry objects, each of which contain geometrical data such as vertices, normals, etc.
     */
    private function get_subGeometries() : Vector<SubGeometry>
    {
        
        return _subGeometries ;
        
    }
    
    
    /**
     * Adds a new SubGeometry object to the list.
     * @param subGeometry The SubGeometry object to be added.
     */
    public function addSubGeometry( subGeometry : SubGeometry )
    {
        
        _subGeometries.push( subGeometry ) ;
        
        subGeometry.parentGeometry = this ;
        if( hasEventListener( GeometryEvent.SUB_GEOMETRY_ADDED ) )
        {
            
            dispatchEvent( new GeometryEvent( GeometryEvent.SUB_GEOMETRY_ADDED, subGeometry ) ) ;
            
        }
        
        invalidateBounds( subGeometry ) ;
        
    }
    
    
    /**
     * Removes a new SubGeometry object from the list.
     * @param subGeometry The SubGeometry object to be removed.
     *
     * todo: consider signals instead of events?
     */
    public function removeSubGeometry( subGeometry : SubGeometry )
    {
        
        _subGeometries.splice( _subGeometries.indexOf( subGeometry ), 1 ) ;
        subGeometry.parentGeometry = null ;
        
        if( hasEventListener( GeometryEvent.SUB_GEOMETRY_REMOVED ) )
        {
            
            dispatchEvent( new GeometryEvent( GeometryEvent.SUB_GEOMETRY_REMOVED, subGeometry ) ) ;
            
        }
        
        invalidateBounds( subGeometry ) ;
        
    }
    
    
    /**
     * Clones the geometry.
     * @return An exact duplicate of the current Geometry object.
     */
    public function clone() : Geometry
    {
        
        var clone           = new Geometry() ;
        clone._animation    = _animation ;
        var len             = _subGeometries.length ;
        
        for ( i in 0...len )
        {
            
            clone.addSubGeometry( _subGeometries[ i ].clone() ) ;
            
        }
        
        return clone ;
        
    }
    
    
    /**
     * Scales the geometry.
     * @param scale The amount by which to scale.
     */
    public function scale( scale : Float )
    {
        
        var numSubGeoms : uint = _subGeometries.length ;
        
        for ( i in 0...numSubGeoms )
        {
            
            _subGeometries[ i ].scale( scale ) ;
            
        }
        
    }
    
    
    /**
     * Clears all resources used by the Geometry object, including SubGeometries.
     */
    public function dispose()
    {
        
        var numSubGeoms = _subGeometries.length ;
        
        for( i in 0...numSubGeoms )
        {
            
            var subGeom = _subGeometries.shift() ;
            removeSubGeometry( subGeom ) ;
            subGeom.dispose() ;
            
        }
        
    }
    
    
    /**
     * Scales the uv coordinates.
     * @param scale The amount by which to scale.
     */
    public function scaleUV( scale : Float )
    {
        
        var numSubGeoms = _subGeometries.length ;
        
        for ( i in 0...numSubGeoms )
        {
            
            _subGeometries[ i ].scaleUV( scale ) ;
            
        }
        
    }
    
    
    public function invalidateBounds( subGeom : SubGeometry )
    {
        
        if( hasEventListener( GeometryEvent.BOUNDS_INVALID ) )
        {
            
            dispatchEvent( new GeometryEvent( GeometryEvent.BOUNDS_INVALID, subGeom ) ) ;
            
        }
    }
    
    
}
